#include "LPC11xx.h"
#include "spi.h"
#include "delay.h"
#include "bitops.h"
#include "rfid.h"
#include <string.h>

void rfid_init(void)
{
  //将PIO2_7配置为片选引脚
  setbits(LPC_IOCON->PIO2_7, 0, 2, 0);
  
  //启用GPIO模块时钟
  setbit(LPC_SYSCON->SYSAHBCLKCTRL, 6);
  
  //将PIO2_7配置为输出模式
  setbit(LPC_GPIO2->DIR, 7);
  
  //片选引脚默认输出高电平
  setbit(LPC_GPIO2->DATA, 7);
  
  //将PIO2_8引脚配置为输入模式
  clrbit(LPC_GPIO2->DIR, 8);
}

//判断是否有卡
int rfid_present(void)
{
  return !chkbit(LPC_GPIO2->DATA, 8);
}

//发送一个字节，将收到字节丢弃
void rfid_send(uint8_t byte)
{
  //发送前拉低片选线
  clrbit(LPC_GPIO2->DATA, 7);
  spi0_send(byte);
  //发送后拉高片选线
  setbit(LPC_GPIO2->DATA, 7);
  delay_ms(1);
}

//接收一个字节，发送全0字节
uint8_t rfid_recv(void)
{
  uint8_t byte = 0;
  //接收前拉低片选线
  clrbit(LPC_GPIO2->DATA, 7);
  byte = spi0_recv();
  //接收后拉高片选线
  setbit(LPC_GPIO2->DATA, 7);
  delay_ms(1);
  return byte;
}

//计算消息校验和
//计算方法：计算所有字节的异或值
char chksum(char * buf, int size)
{
  int i;
  char val = 0;
  
  for(i = 0; i < size; i++)
  {
    val ^= buf[i];
  }
  
  return val;
}

//从RFID卡中读取一个数据块
int rfid_read_block(uint8_t block[16])
{
  int i = 0;
  char command[] = {0xAA, 0xBB, /*前导头*/
                    0x0A,       /*数据长度*/
                    0x21,       /*命令字*/
                    0,          /*密钥标志*/
                    0,          /*块号*/
                    0,0,0,0,0,0,/*6字节密钥*/
                    0           /*校验和*/
  };
  //成功的响应消息中包含21个字节
  uint8_t response[21];
  
  command[sizeof(command) - 1] = chksum(&command[2], 10);
  
  //发送命令
  //printf("> ");
  for (i = 0; i < sizeof(command); i++)
  {
    rfid_send(command[i]);
    //打印发送的消息内容
    //printf("%02x ", command[i]);
  }
  //printf("\r\n");
  
  //等待RFID模块响应，延时50ms
  delay_ms(50);
  
  //接收从设备响应

  //接收前导头
  response[0] = rfid_recv();
  response[1] = rfid_recv();
  //判断前导头是否正确
  if(response[0] != 0xAA || response[1] != 0xBB)
  {
    //printf("header error: %02x %02x\r\n", response[0], response[1]);
    return 1;
  }
  //接收长度字段
  response[2] = rfid_recv();
  //打印接收到的响应消息内容
  //printf("< 0xaa 0xbb %02x ", response[2]);
  //接收响应消息中剩余的字节
  for (i = 3; i < response[2] + 2; i++)
  {
    response[i] = rfid_recv();
    //printf("%02x ", response[i]);
  }
  //从机发送的长度字段错误，应该再接收一个字节
  response[i] = rfid_recv();
  //printf("%02x\r\n", response[i]);
  
  memcpy(block, &response[4], 16);
  
  return 0;
}

int rfid_write_block(uint8_t* data, int size)
{
  char command[] = {0xAA, 0xBB, /*前导头*/
                    0x1A,       /*数据长度*/
                    0x22,       /*命令字*/
                    0,          /*密钥标志*/
                    0,          /*块号*/
                    0,0,0,0,0,0,/*6字节密钥*/
                    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /*16字节数据*/
                    0           /*校验和*/
  };
  //成功的响应消息中包含21个字节
  uint8_t response[5];
  int i = 0;
  
  if (size > 16)
  {
    size = 16;
  }
  
  //拷贝数据到命令缓冲区
  memcpy(&command[12], data, size);
  
  //计算校验和
  command[sizeof(command) - 1] = chksum(&command[2], sizeof(command) - 3);
  
  //发送命令
  //printf("> ");
  for (i = 0; i < sizeof(command); i++)
  {
    rfid_send(command[i]);
    //打印发送的消息内容
    //printf("%02x ", command[i]);
  }
  //printf("\r\n");
  
  //等待RFID模块响应，延时50ms
  delay_ms(50);
  
  //接收从设备响应

  //接收前导头
  response[0] = rfid_recv();
  response[1] = rfid_recv();
  //判断前导头是否正确
  if(response[0] != 0xAA || response[1] != 0xBB)
  {
    //printf("header error: %02x %02x\r\n", response[0], response[1]);
    return 1;
  }
  //接收长度字段
  response[2] = rfid_recv();
  //打印接收到的响应消息内容
  //printf("< aa bb %02x ", response[2]);
  //接收响应消息中剩余的字节
  for (i = 3; i < response[2] + 2; i++)
  {
    response[i] = rfid_recv();
    //printf("%02x ", response[i]);
  }
  //printf("\r\n");
  
  return 0;
}
